#include "head.h"

extern char token[512];

int puts_handler(int socket_fd, long_command_t long_command){

    //判断本地是否存在需要上传文件
    int is_exist_file = open(long_command.argument, O_RDWR);
    if(is_exist_file == -1){
        printf("该文件不存在，请重新输入！\n");
        return 0;
    }

    //拼接发送给服务端的信息
    transmit_t transmit;
    bzero(&transmit,sizeof(transmit));
    strcpy(transmit.flag, "LONGCOMMAND");
    strcpy(transmit.token,token);
    strcpy(transmit.command,long_command.command);
    strcpy(transmit.argument,long_command.argument);
    send(socket_fd,&transmit,sizeof(transmit),MSG_NOSIGNAL);


    //先计算要上传的文件的hash值，发送给服务端
    //接受服务端的信号，看文件是否秒传
    char file_hash[41] = { 0 }; //sha1的hash值为40个字符，加上字符串最后的空字符
    //计算文件的hash值
    //printf("计算文件的hash值\n");
    hash_sha1(file_hash, long_command);
    //发送文件的hash值给服务端
    //printf("发送hash值给服务端\n");
    send_train(file_hash, socket_fd);

    //尝试接收是否秒传信息
    //若是秒传，则会接收到 极速秒传成功！
    //若不是秒传，则会接收到 正在上传文件，请稍等...
    //若正在上传重复文件，则会接收到 当前路径下已有该文件，上传失败!
    char buf[256] = {0};
    bzero(buf, sizeof(buf));
    recv_train(buf, socket_fd);
    printf("%s\n", buf);

    if(strcmp(buf, "极速秒传成功！") == 0){
        //是极速秒传，关闭网络文件描述符，然后返回
        close(socket_fd);
        return 0;
    } 
    if(strcmp(buf, "当前路径下已有该文件，上传失败!") == 0){
        close(socket_fd);
        return 0;
    }
    //运行到这里，证明不满足秒传条件，则需要继续发送文件内容给服务端
    //获取并发送文件大小给服务端
    int file_fd = open(long_command.argument, O_RDWR);
    struct stat st;
    bzero(&st, sizeof(st));
    fstat(file_fd, &st);
    //printf("file_size: %ld \n", st.st_size);
    //把文件大小发送给服务端
    send(socket_fd, &st.st_size, sizeof(off_t), MSG_NOSIGNAL);
    
    //接收文件指针位置
    off_t location = 0;
    recv(socket_fd,&location,sizeof(off_t),MSG_WAITALL);
    int count = st.st_size - location;

    // 使用sendfile: 零拷贝
    sendfile(socket_fd, file_fd, &location, count);
    puts("发送完成");
    close(file_fd);

    //尝试接收文件上传成功
    char is_secess[256];
    recv_train(is_secess, socket_fd);
    printf("%s\n", is_secess);
    //关闭网络文件描述符
    close(socket_fd);
    return 0;
}

#define MAX_FILENAME_LENGTH 255
int open_unique_file(const char * file_name,const off_t file_size);
int gets_handler(int socket_fd, long_command_t long_command){
    //puts("开始处理下载请求"); 
    
    //拼接发送给服务端的信息
    transmit_t transmit;
    bzero(&transmit,sizeof(transmit));
    strcpy(transmit.flag, "LONGCOMMAND");
    strcpy(transmit.token,token);
    strcpy(transmit.command,long_command.command);
    strcpy(transmit.argument,long_command.argument);
    send(socket_fd,&transmit,sizeof(transmit),MSG_NOSIGNAL);
    
    //从参数提取文件名
    char buf[256] = {0};
    char file_name[255] = {0};
    strncpy(buf,long_command.argument,strcspn(long_command.argument," "));
    strncpy(file_name,long_command.argument,strcspn(long_command.argument," ")); 
    int len = strlen(buf);
    int ret = send(socket_fd,&len,sizeof(int),0);
    ret = send(socket_fd,buf,len,0);
    puts("下载请求已发送");   
    //接收查找结果
    ret = recv(socket_fd,&len,sizeof(int),MSG_WAITALL);
    ret = recv(socket_fd,buf,len,MSG_WAITALL);

    if(strcmp(buf,"此文件不存在") == 0) {
        printf("文件不存在\n");
        return 0;
    } 

    if(strcmp(buf,"文件已找到") == 0) {
        printf("开始下载\n");
    }
    
    //接收文件大小
    off_t file_size = 0;
    ret = recv(socket_fd,&len,sizeof(int),MSG_WAITALL);
    ret = recv(socket_fd,&file_size,len,MSG_WAITALL);

    //设置下载位置，打开文件
    char download_locatin[256] = "../download/";
    strcat(download_locatin,file_name);
    int file_fd = open_unique_file(download_locatin,file_size);
    if(file_fd == -1) {
        printf("文件打开失败\n");
        return 0;
    }

   
    //文件大小同步
    ftruncate(file_fd,file_size);

    //需要下载的剩余文件大小
    off_t remain_size = file_size;
    off_t recv_size = 0;
    char buffer[4096] = {0};

    while(recv_size < remain_size) {
        off_t buf_size = remain_size - recv_size > (off_t)sizeof(buffer) ? (off_t)sizeof(buffer) : remain_size - recv_size;
        char *file_p = (char *)mmap(NULL,buf_size,PROT_READ | PROT_WRITE,MAP_SHARED,file_fd,recv_size);
        if(file_p == MAP_FAILED) {
            puts("mmap failed");
            return 0;
        }
        ret = recv(socket_fd,buffer,buf_size,MSG_WAITALL);
        memcpy(file_p,buffer,buf_size);
        recv_size += buf_size;
        //location += buf_size;
        munmap(file_p,buf_size);
    }   
    puts("");
    puts("文件下载完成");
    close(file_fd);

    //关闭网络文件描述符
    close(socket_fd);    
    return 0;
}


int open_unique_file(const char *filename,const off_t file_size) {
    char new_filename[MAX_FILENAME_LENGTH] = {0};
    int file_fd;
    int counter = 0;

    strncpy(new_filename, filename, MAX_FILENAME_LENGTH - 1);
    new_filename[MAX_FILENAME_LENGTH - 1] = '\0';
    
    struct stat file_info;
    bzero(&file_info,sizeof(file_info));

    while ((file_fd = open(new_filename, O_CREAT | O_EXCL | O_RDWR, 0644)) == -1) {
        if (errno == EEXIST) {
            counter++;
            snprintf(new_filename, MAX_FILENAME_LENGTH, "%s_%d", filename, counter);
        } else {
            perror("无法创建文件");
            return -1; 
        }
    }
   return file_fd;
}


















